package com.agileai.esb.smc.servlet;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Timer;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.activemq.broker.BrokerService;
import org.apache.log4j.Logger;
import org.logicalcobwebs.proxool.ProxoolFacade;

import com.agileai.domain.DataMap;
import com.agileai.domain.DataParam;
import com.agileai.domain.DataRow;
import com.agileai.esb.component.manager.DBResourceManager;
import com.agileai.esb.component.manager.LoggerManager;
import com.agileai.esb.component.manager.PropertiesResourceManager;
import com.agileai.esb.core.SoakerContants;
import com.agileai.esb.smc.bizmoduler.analysis.MessageFlowStatManage;
import com.agileai.esb.smc.bizmoduler.analysis.WebServiceStatManage;
import com.agileai.esb.smc.bizmoduler.sysres.DbResourceManage;
import com.agileai.esb.smc.bizmoduler.sysres.DbTemplateManage;
import com.agileai.esb.smc.bizmoduler.sysres.SkAppManage;
import com.agileai.esb.smc.bizmoduler.sysres.SysFuncBaseTreeManage;
import com.agileai.esb.smc.bizmoduler.sysres.VarDefineManage;
import com.agileai.esb.smc.common.MfStatisticsTask;
import com.agileai.esb.smc.common.WsStatisticsTask;
import com.agileai.esb.smc.domain.User;
import com.agileai.hotweb.common.BeanFactory;
import com.agileai.hotweb.common.Constants;
import com.agileai.hotweb.common.Constants.FrameHandlers;
import com.agileai.hotweb.common.HandlerParser;
import com.agileai.hotweb.controller.core.BaseHandler;
import com.agileai.hotweb.domain.FormSelect;
import com.agileai.hotweb.domain.FormSelectFactory;
import com.agileai.hotweb.domain.core.Profile;
import com.agileai.hotweb.renders.AjaxRenderer;
import com.agileai.hotweb.renders.RedirectRenderer;
import com.agileai.hotweb.renders.ViewRenderer;
import com.agileai.hotweb.servlet.DispatchServlet;
import com.agileai.util.ListUtil;
import com.agileai.util.StringUtil;

public class SoakerDispatchServlet extends DispatchServlet {
	private static final long serialVersionUID = 2253354391148388263L;
	public static ServletContext servletContext = null; 
	private static BrokerService broker;
	private static List<String> publicHandlerIdList= new ArrayList<String>();

	protected void initResource(){
		servletContext = getServletContext();
		this.initPublicHandlerIds();
		this.initRootLogger();
		this.initDataSources();		
		this.initPropertiesConfig();
		this.initEmbedActiveMq();
		this.initMfStatisticsTaskTimer();
		this.initWsStatisticsTaskTimer();
	}
	
	private void initPublicHandlerIds(){
		String publicHandlerIds = getInitParameter("publicHandlerIds");
		if (StringUtil.isNotNullNotEmpty(publicHandlerIds)){
			ListUtil.addArrayToList(publicHandlerIdList, publicHandlerIds.split(","));
		}
	}
	
	protected void initEmbedActiveMq() {
		String mqconn = getInitParameter("mqconn");
		String mqStart = getInitParameter("mqstart");
		log.info("initEmbedActiveMq ....");
		if (Boolean.parseBoolean(mqStart)) {
	        try {
		        broker = new BrokerService();
		        broker.setUseJmx(false);
				broker.addConnector(mqconn);
		        broker.setDataDirectory(getDataPath());
		    	broker.start();
		    	log.info("initEmbedActiveMq successfully !");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	protected void initMfStatisticsTaskTimer(){
		MessageFlowStatManage messageFlowStatManage = (MessageFlowStatManage) BeanFactory.instance().getBean("messageFlowStatManageService");
		Timer timer = new Timer();
		MfStatisticsTask statisticsTask = new MfStatisticsTask(messageFlowStatManage);
		String timerDelay = PropertiesResourceManager.instance().getConfigProperty("GlobalConfigs", "MfStatTimerTaskDelay","600000");
		String timerPeriod = PropertiesResourceManager.instance().getConfigProperty("GlobalConfigs", "MfStatTimerTaskPeriod","3600000");
		timer.schedule(statisticsTask,Long.parseLong(timerDelay), Long.parseLong(timerPeriod));
	}
	
	protected void initWsStatisticsTaskTimer(){
		WebServiceStatManage webServicStatManage = (WebServiceStatManage) BeanFactory.instance().getBean("webServiceStatManageService");
		Timer timer = new Timer();
		WsStatisticsTask statisticsTask = new WsStatisticsTask(webServicStatManage);
		String timerDelay = PropertiesResourceManager.instance().getConfigProperty("GlobalConfigs", "WsStatTimerTaskDelay","600000");
		String timerPeriod = PropertiesResourceManager.instance().getConfigProperty("GlobalConfigs", "WsStatTimerTaskPeriod","3600000");
		timer.schedule(statisticsTask,Long.parseLong(timerDelay), Long.parseLong(timerPeriod));
	}
	
	public static String getApplicationPath(String appName){
		String result = null;
		String realPath = servletContext.getRealPath("/");
		String tempPath = realPath.replaceAll("\\\\", "/");
		if (tempPath.endsWith("/")){
			tempPath = tempPath.substring(0,tempPath.length()-1);
			result = tempPath.substring(0,tempPath.lastIndexOf("/"))+"/"+appName;
		}else{
			result = tempPath.substring(0,tempPath.lastIndexOf("/"))+appName;
		}
		return result;
	}
	public static String getSoakerPort(){
		String soakerPort = servletContext.getInitParameter(SoakerContants.SoakerPortKey);
		return soakerPort;
	}
	
	public static String getToDeployPath(){
		String result = null;
		String realPath = servletContext.getRealPath("/");
		String tempPath = realPath.replaceAll("\\\\", "/");
		if (tempPath.endsWith("/")){
			tempPath = tempPath.substring(0,tempPath.length()-1);
		}
		tempPath = tempPath.substring(0,tempPath.lastIndexOf("/"));
		result = tempPath.substring(0,tempPath.lastIndexOf("/"))+ "/todeploy";
		return result;
	}
	
	public static String getRootLog4jPath(){
		String result = null;
		String realPath = servletContext.getRealPath("/");
		String tempPath = realPath.replaceAll("\\\\", "/");
		if (tempPath.endsWith("/")){
			tempPath = tempPath.substring(0,tempPath.length()-1);
		}
		tempPath = tempPath.substring(0,tempPath.lastIndexOf("/"));
		result = tempPath.substring(0,tempPath.lastIndexOf("/"))+ "/webapps/SMC/WEB-INF/classes/log4j.properties";
		return result;
	}
	
	public static String getReponsitoryPath(){
		String result = null;
		String realPath = servletContext.getRealPath("/");
		String tempPath = realPath.replaceAll("\\\\", "/");
		if (tempPath.endsWith("/")){
			tempPath = tempPath.substring(0,tempPath.length()-1);
		}
		tempPath = tempPath.substring(0,tempPath.lastIndexOf("/"));
		result = tempPath.substring(0,tempPath.lastIndexOf("/"))+ "/reponsitory";
		return result;
	}
	
	public static String getDataPath(){
		String result = null;
		String realPath = servletContext.getRealPath("/");
		String tempPath = realPath.replaceAll("\\\\", "/");
		if (tempPath.endsWith("/")){
			tempPath = tempPath.substring(0,tempPath.length()-1);
		}
		tempPath = tempPath.substring(0,tempPath.lastIndexOf("/"));
		result = tempPath.substring(0,tempPath.lastIndexOf("/"))+ "/data";
		return result;
	}	
	
	private void initDataSources(){
		try {
			LoggerManager loggerManager = LoggerManager.instance();
			Logger logger  = loggerManager.getRootLogger();
			loggerManager.debugBegin(logger, "initDataSources");
			
			DbResourceManage dbResourceManage = (DbResourceManage)BeanFactory.instance().getBean("dbResourceManageService");
			dbResourceManage.initializeDataSources();
			
			DbTemplateManage dbTemplateManage = (DbTemplateManage)BeanFactory.instance().getBean("dbTemplateManageService");
			List<DataRow> temlateRecords = dbTemplateManage.findRecords(new DataParam());
			List<DataRow> dataBaseRecords = dbResourceManage.findRecords(new DataParam());
			
			DBResourceManager dbResourceManager = DBResourceManager.instance();
			dbResourceManager.init(temlateRecords, dataBaseRecords);
			
			loggerManager.debugEnd(logger, "initDataSources");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private void initPropertiesConfig(){
		try {
			LoggerManager loggerManager = LoggerManager.instance();
			Logger logger  = loggerManager.getRootLogger();
			loggerManager.debugBegin(logger, "initPropertiesConfig");
			
			PropertiesResourceManager manager = PropertiesResourceManager.instance();
			VarDefineManage varDefineManageService = (VarDefineManage)BeanFactory.instance().getBean("varDefineManageService");
			
			List<DataRow> masterRecords = varDefineManageService.findMasterRecords(new DataParam());
			HashMap<String,List<DataRow>> entries = varDefineManageService.queryEntryRecords();
			manager.init(masterRecords, entries);
			
			loggerManager.debugEnd(logger, "initPropertiesConfig");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	private void initRootLogger(){
		try {
			String log4jConfigPath = getRootLog4jPath();
			File file = new File(log4jConfigPath);
			InputStream inputStream = new FileInputStream(file);
			LoggerManager.instance().addRootProperties(inputStream);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static String getWebServicePath(String appName){
		String result = null;
		String appPath = getApplicationPath(appName);
		SkAppManage soakerManage = (SkAppManage)BeanFactory.instance().getBean("skAppManageService");
		DataRow row = soakerManage.getRecord(new DataParam("APP_NAME",appName));
		String mainPkg = row.stringValue("APP_MAINPKG");
		String tempPath = mainPkg.replaceAll("\\.", "/");
		result = appPath + "/" + tempPath+"/"+"services";
		return result;
	}
	
	public static String getMessageFlowPath(String appName,String messageFlowName){
		String result = null;
		SkAppManage soakerManage = (SkAppManage)BeanFactory.instance().getBean("skAppManageService");
		DataRow row = soakerManage.getRecord(new DataParam("APP_NAME",appName));
		String mainPkg = row.stringValue("APP_MAINPKG");
		String tempPath = mainPkg.replaceAll("\\.", "/");
		result = tempPath + "/messageflows/"+messageFlowName.toLowerCase();
		return result;
	}	
	
	protected void process(HttpServletRequest request, HttpServletResponse response) throws ServletException,
			IOException {
		log.debug("DispatchServlet------start");
		try {
			ViewRenderer viewRenderer = null;
			String handlerId = parseHandlerId(request);
			if (isExpired(request) && !Constants.FrameHandlers.LoginHandlerId.equals(handlerId)
					&& !publicHandlerIdList.contains(handlerId)) {
				if (!Constants.FrameHandlers.MenuTreeHandlerId.equals(handlerId)) {
					viewRenderer = new RedirectRenderer(request.getContextPath());
				} else {
					StringBuffer responseText = new StringBuffer();
					String contextPath = request.getContextPath();
					responseText.append("parent.location.href='").append(contextPath).append("'");
					viewRenderer = new AjaxRenderer(responseText.toString());
				}
			} else {
				if (checkValid(request,handlerId)){
					BaseHandler handler = HandlerParser.getOnly().instantiateHandler(handlerId);
					handler.setDispatchServlet(this);
					handler.setRequest(request);
					handler.setResponse(response);
					DataParam param = new DataParam(request.getParameterMap());
					viewRenderer = handler.processRequest(param);
					viewRenderer.setHandler(handler);					
				}
				else{
					viewRenderer = new RedirectRenderer(request.getContextPath());
				}
			}
			viewRenderer.executeRender(this, request, response);
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		log.debug("DispatchServlet------end");
	}
	
	private boolean checkValid(HttpServletRequest request,String handlerId){
		boolean result = false;
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		List<String> publicHandlerIdList = PublicHandlerIdListCache.get(classLoader);
		if (FrameHandlers.LoginHandlerId.equals(handlerId) || publicHandlerIdList.contains(handlerId)){
			return true;
		}
		HttpSession session = request.getSession(false);
		if (session != null){
			Profile profile = (Profile)session.getAttribute(Profile.PROFILE_KEY);
			if (profile != null){
				User user = (User)profile.getUser();
				if (user != null){
					if (user.isAdmin()){
						return true;
					}
					if (isAuthedHandlerId(handlerId)){
						return true;
					}
					String currentFunctionId = user.getCurrentFuncId();
					
					BeanFactory beanFactory = BeanFactory.instance();
					SysFuncBaseTreeManage baseTreeManage = (SysFuncBaseTreeManage)beanFactory.getBean("sysFuncBaseTreeManageService");
					HashMap<String,List<String>> handlerIdListMap = baseTreeManage.getHandlerIdMap();
					if (handlerIdListMap != null){
						List<String> handlerIdList = handlerIdListMap.get(currentFunctionId);
						if (handlerIdList != null && handlerIdList.contains(handlerId)){
							result = true;
						}
					}
				}
			}
		}
		return result;
	}
		
	private boolean isAuthedHandlerId(String handlerId){
		boolean result = false;
		FormSelect formSelect = FormSelectFactory.create("AuthedHandlerId");
		if (formSelect != null){
			DataMap map = formSelect.getContent();
			if (map != null && map.containsKey(handlerId)){
				result = true;
			}
		}
		return result;
	}
	
	@Override
	public void destroy() {
		super.destroy();
		try {
			if (broker != null) {
				broker.stop();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		ProxoolFacade.shutdown();
	}
}
